package com.lottery.game.websocket.interceptor;

import com.lottery.game.common.utils.MapUtils;
import com.lottery.game.common.utils.UUIDUtils;
import com.lottery.game.core.model.dto.UserToken;
import com.lottery.game.core.modules.service.app.OnlineAppContext;
import com.lottery.game.core.modules.service.app.OperationalSetService;
import com.lottery.game.core.modules.service.app.WebsocketMessageService;
import com.lottery.game.core.modules.service.app.v2.PassportService;
import com.lottery.game.core.modules.service.redis.RedisService;
import com.lottery.game.core.utils.HeaderAcessorUtils;
import com.lottery.game.websocket.WsUtils;
import com.lottery.game.websocket.listener.ConnectEventListener;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.messaging.SessionConnectEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;

import lombok.extern.slf4j.Slf4j;

import static com.lottery.game.common.constants.GameConstants.CHATTYPE_CONNECT;
import static com.lottery.game.common.constants.GameConstants.CHATTYPE_CUSREPLY;
import static com.lottery.game.common.constants.GameConstants.CHATTYPE_CUSSERVICECHAT;
import static com.lottery.game.common.constants.GameConstants.CHATTYPE_GROUPCHAT;
import static com.lottery.game.common.constants.GameConstants.CHATTYPE_SYSTEM_MSG;
import static com.lottery.game.common.constants.GameConstants.CHAT_ID;
import static com.lottery.game.common.constants.GameConstants.CHAT_TYPE;
import static com.lottery.game.common.constants.GameConstants.CHAT_TYPE_ROOM_MSG;
import static com.lottery.game.common.constants.GameConstants.RANDOM_USER_ID;
import static com.lottery.game.common.constants.GameConstants.ROOM_NUMBER;
import static com.lottery.game.common.constants.GameConstants.SYS_MSG_CUSSERVICECHAT_NOTICE;
import static com.lottery.game.common.constants.GameConstants.SYS_MSG_SXFEN_COUNT;
import static com.lottery.game.common.constants.GameConstants.SYS_OVERALL;
import static com.lottery.game.common.constants.GameConstants.SYS_PARAM_CHATID;
import static com.lottery.game.common.constants.GameConstants.USER_ID;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

@Slf4j
@Component
public class InboundChannelInterceptorAdapter implements ChannelInterceptor {

//	private GameUserService gameUserService;
//	private WebSocketService webSocketService;
//	private ChatRecordService chatRecordService;

	private RedisService redisFeignClient;
	
	private PassportService passportService;
	
	private Integer serverPort;
	
	private OnlineAppContext onlineAppContext;
	
	private OperationalSetService operationalSetService;
	
	private WebsocketMessageService websocketMessageServcie;

//	public InboundChannelInterceptorAdapter(GameUserService gameUserService, WebSocketService webSocketService,
//			ChatRecordService chatRecordService) {
//		this.gameUserService = gameUserService;
//		this.webSocketService = webSocketService;
//		this.chatRecordService = chatRecordService;
//	}

	public InboundChannelInterceptorAdapter() {
	}
	
	public InboundChannelInterceptorAdapter(WebsocketMessageService websocketMessageService,RedisService redisFeignClient,PassportService passportService
			,Integer serverPort,OnlineAppContext onlineAppContext,OperationalSetService operationalSetService) {
		this.websocketMessageServcie = websocketMessageService;
		this.redisFeignClient = redisFeignClient;
		this.passportService = passportService;
		this.serverPort = serverPort;
		this.onlineAppContext = onlineAppContext;
		this.operationalSetService = operationalSetService;
	}
	
	public InboundChannelInterceptorAdapter(WebsocketMessageService websocketMessageServcie) {
		this.websocketMessageServcie = websocketMessageServcie;
	}

	@Override
	public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, Exception ex) {
		ChannelInterceptor.super.afterSendCompletion(message, channel, sent, ex);
	}

	@Override
	public void afterReceiveCompletion(Message<?> message, MessageChannel channel, Exception ex) {
		ChannelInterceptor.super.afterReceiveCompletion(message, channel, ex);
	}

	@Override
	public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
		StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);//消息头访问器
		StompCommand command = accessor.getCommand();

		Boolean isHeartBeat = accessor.isHeartbeat();
		if(isHeartBeat) {
			// sent heart beat message
			log.info("   ---heartbeat---inbound---");
			return;
		}

		if (command == null) {
			log.info("   ------------command111:   {}", command);
			return ;// 避免非stomp消息类型，例如心跳检测
		}
		log.info("   ------------command222:   {}, chatType: {}", command, accessor.getSessionAttributes().get(CHAT_TYPE));

		switch (command) {
		case CONNECT:
			// connect -> ConnectEventListener
			//ConnectEventListener cl = new ConnectEventListener();
			//cl.onApplicationEvent(event);
			this.connect(accessor);
			break;
		case DISCONNECT:
			// disconnect -> DisconnectEventListener
			this.disconnect(accessor);
			break;
		case SUBSCRIBE:

			break;
		case SEND:
			break;
		case UNSUBSCRIBE:

			break;
		case ACK:
			ack(accessor);
			break;
		default:
			break;
		}
	}

	private void ack(StompHeaderAccessor accessor) {
		log.info("  确认信息：{}", HeaderAcessorUtils.getIfExistFromHeader(accessor, "ack"));
//		log.info("   ---ack---accessor:{}   ", accessor);
//		String receipt = accessor.getReceipt();
//		log.info("   ---ack---receipt:{}   ", receipt);

		String messageId = HeaderAcessorUtils.getIfExistFromHeader(accessor, "ack");

		websocketMessageServcie.updateWebsocketMessageStatus(messageId);
	}
	
	public void connect(StompHeaderAccessor accessor) {
		log.info("Connect, 1 - command:  {}", accessor.getCommand());
//		Principal principal = accessor.getUser();
//		log.info("Connect, 2 - principal:  {}", principal);
//
//		if(principal != null) {
//			log.info("Connect, 3 - name:  {}", principal.getName());
//		}

		String sessionId = accessor.getSessionId();
		log.info("Connect, 2 - sessionId: {}", sessionId);
		String login = accessor.getLogin();
		String passcode = accessor.getPasscode();
		String receiptId = accessor.getReceiptId();
		String message = accessor.getMessage();
		MessageHeaders messageHeaders = accessor.getMessageHeaders();
		
		log.info("Connect, 3 - login: {}, passcode: {}", login, passcode);
		log.info("Connect, 4 - receiptId: {}", receiptId);

//		Collection<Object> headers = messageHeaders.values();

		Set<Entry<String, Object>> headers = messageHeaders.entrySet();
		//String userId = null;

		String clientId = getIfExistFromHeader(accessor, "client-id");
		String ticket = getIfExistFromHeader(accessor, "ticket");
		String chatType = getIfExistFromHeader(accessor, CHAT_TYPE);
		String chatId = getIfExistFromHeader(accessor, CHAT_ID);
		String roomId = getIfExistFromHeader(accessor, ROOM_NUMBER);
		String userId = getIfExistFromHeader(accessor, USER_ID);
		log.info("Connect, 8.5 - chatType: {}", chatType);
		log.info("Connect, 8.6 - ticket: {}", ticket);
		log.info("Connect, 8.7 - chatId: {}", chatId);
		log.info("Connect, 8.8 - roomId: {}", roomId);
		log.info("Connect, 8.9 - userId: {}", userId);
		if(chatType == null) {
			return;
		}

		try {
			UserToken userToken = MapUtils.mapToObject(passportService.checkToken(ticket), UserToken.class);
			userId = userToken.getId();
			if(org.apache.commons.lang3.StringUtils.isBlank(userId)) {
				return;
			}
			redisFeignClient.set(WsUtils.buildKey(serverPort, sessionId, userId), System.currentTimeMillis() + "");
		} catch (Exception e) {
			log.error("ticket invalid error", e);
			return;
		}

		switch (chatType) {
		// 群聊
		case CHATTYPE_GROUPCHAT:
			if (StringUtils.isEmpty(userId)) {
				userId = UUIDUtils.randomUUID();
			}
			accessor.getSessionAttributes().put(USER_ID, userId);
			accessor.getSessionAttributes().put(ROOM_NUMBER, roomId);
			accessor.getSessionAttributes().put(CHAT_ID, roomId);
			chatId = roomId;
			break;
		// 客服聊天
		case CHATTYPE_CUSSERVICECHAT:
			chatId = (chatId == null) ? userId : chatId;
			accessor.getSessionAttributes().put(USER_ID, userId);
			accessor.getSessionAttributes().put(CHAT_ID, roomId);
			break;
		case CHATTYPE_CUSREPLY:
			chatId = (chatId == null) ? userId : chatId;
			accessor.getSessionAttributes().put(USER_ID, userId);
			accessor.getSessionAttributes().put(CHAT_ID, roomId);
			break;
		case CHATTYPE_SYSTEM_MSG:
			accessor.getSessionAttributes().put(USER_ID, userId);
			accessor.getSessionAttributes().put(CHAT_ID, SYS_PARAM_CHATID);
			//chatId = SYS_PARAM_CHATID;
			break;
		case SYS_OVERALL:
			String randomUserId = UUIDUtils.randomUUID();
			accessor.getSessionAttributes().put(RANDOM_USER_ID, randomUserId);
			accessor.getSessionAttributes().put(CHAT_ID, chatType);
			break;
		case SYS_MSG_SXFEN_COUNT: // 上下分消息传递
			accessor.getSessionAttributes().put(USER_ID, userId);
			accessor.getSessionAttributes().put(CHAT_ID, chatType);
			break;
		case SYS_MSG_CUSSERVICECHAT_NOTICE: //客服消息通知传递
			accessor.getSessionAttributes().put(USER_ID, userId);
			accessor.getSessionAttributes().put(CHAT_ID, chatType);
			break;
		case CHAT_TYPE_ROOM_MSG:
			userId = StringUtils.isEmpty(userId) ? UUIDUtils.randomUUID() : userId;
			accessor.getSessionAttributes().put(USER_ID, userId);
			accessor.getSessionAttributes().put(ROOM_NUMBER, roomId);
			accessor.getSessionAttributes().put(CHAT_ID, "roomMsg|" + roomId);
			chatId = "roomMsg|" + roomId;
			break;
		case CHATTYPE_CONNECT:
			/*try {
				this.afterConnectEstablished(accessor);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}*/
			break;
		default:
			break;
		}
		try {
			this.afterConnectEstablished(chatId,userId);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}
	
	private void afterConnectEstablished(String chatId,String userId) {
		//MessageHeaders headers = accessor.toMessageHeaders();
		/*Set<String> keys = headers.keySet();
		for (String key : keys) {
			log.info("   header  [{}] - {}", key, headers.get(key));
		}*/
		//String chatId = getIfExistFromHeader(accessor, CHAT_ID);
		//String ticket = getIfExistFromHeader(accessor, "ticket");
		//String userId = getIfExistFromHeader(accessor, USER_ID);
		//String roomNumber = getIfExistFromHeader(accessor, ROOM_NUMBER);
		//TODO
		//String userId = "";
		//String userId = TokenUtils.getUserId(token);

		//accessor.getSessionAttributes().put(CHAT_ID, chatId);
		//accessor.getSessionAttributes().put(USER_ID, userId);

		log.info("   ---afterConnectEstablished.chatId:   {}", chatId);

		if(chatId.equals(SYS_OVERALL)) {
			/*Set<String> userIdList = onlineAppContext.getUserIdsByRoomNumber(roomNumber);
			if (userIdList == null) {
				userIdList = new CopyOnWriteArraySet<String>();
			}*/
			//String randomUserId = (String) accessor.getSessionAttributes().get(RANDOM_USER_ID);
			//onlineAppContext.putUserIds(chatId, randomUserId);
		}else {
			/*Set<String> list = onlineAppContext.getUserIds(chatId);
			if (list == null) {
				list = new CopyOnWriteArraySet<String>();
			}*/
			onlineAppContext.putUserIds(chatId, userId);
		}

		//推送真实人数消息 和虚拟人数
		int number = onlineAppContext.getUserIds(chatId).size();

//		RealNumberObj realNumber=new RealNumberObj();
//		realNumber.setRoomNumber(chatId);
//		realNumber.setRoomPeople(number);
//		realNumber.setStatus("add");

		//查询是否有虚拟人数
		List<Map<String, Object>> list=null;
		int random =0;
		if(!StringUtils.isEmpty(chatId) && !SYS_OVERALL.equals(chatId)) {
			list = operationalSetService.queryVirtualNumberSetByNum(chatId);
			if(!CollectionUtils.isEmpty(list)) {
				String randoms = redisFeignClient.get(chatId);
				if(!StringUtils.isEmpty(randoms)) {
					random = Integer.parseInt(randoms);
				}
			}else {
				redisFeignClient.delete(chatId);
			}
		}

//		realNumber.setRandomNumber(random);
//		RoomRealNumberObj rn = new RoomRealNumberObj(realNumber);
//
//		String sendMsg = JSONObject.toJSONString(rn);
//		webSocketService.sendToEveryChatUser(sendMsg, chatId);
	}
	
	private String getIfExistFromHeader(StompHeaderAccessor accessor, String key) {
		return accessor.getFirstNativeHeader(key);
	}
	
	//222
	public void disconnect(StompHeaderAccessor accessor) {
		//StompHeaderAccessor accessor =  StompHeaderAccessor.wrap(event.getMessage());
		log.info("Disconnected");

		String chatId = getIfExistFromHeader(accessor, CHAT_ID);
		String userId = getIfExistFromHeader(accessor, USER_ID);
		String randomUserId= getIfExistFromHeader(accessor, RANDOM_USER_ID);

		accessor.getSessionAttributes().remove(RANDOM_USER_ID, randomUserId);
		accessor.getSessionAttributes().remove(USER_ID, userId);

		List<Map<String, Object>> list=null;
//		int count = 0;
		if(!StringUtils.isEmpty(chatId) && !chatId.equals("sys_Overall")) {
			list = this.operationalSetService.queryVirtualNumberSetByNum(chatId);
//			if(!CollectionUtils.isEmpty(list)) {
//				String randoms = this.redisFeignClient.get(chatId);
//				if(!StringUtils.isEmpty(randoms)) {
//					count = Integer.parseInt(randoms);
//				}
//			} else {
//				this.redisFeignClient.del(chatId);
//			}
			if(CollectionUtils.isEmpty(list)) {
				this.redisFeignClient.delete(chatId);
			}
		}

		String sessionId = accessor.getSessionId();
		Set<String> keys = redisFeignClient.keys("*" + sessionId + "*");
		if(!CollectionUtils.isEmpty(keys)) {
			for (String key : keys) {
				redisFeignClient.delete(key);
			}
		}
	}

}
